#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<sys/wait.h>
#include<sys/types.h>
#include<stdlib.h>
#include<assert.h>
#include<sys/stat.h>
#include<fcntl.h>
#define NUM 1024
#define SIZE 32
#define SEP " "

char  cmd_arg[NUM];
char* g_val[SIZE];
char my_val[100];
#define APPEND_REDIR 1
#define INPUT_REDIR 2
#define OUTPUT_REDIR 3
#define NONE_REDIR 0


int _status=NONE_REDIR;
char* check_redir(char* str)
{
    assert(str);
    char* end=str+strlen(str)-1;
    while(end>=str)
    {
        if(*end=='>')
        {
            if(*(end-1)=='>')
            {
                _status=APPEND_REDIR;
                *(end-1)='\0';
                end++;
                break;
            }
            _status=OUTPUT_REDIR;
            *(end)='\0';
            end++;
            break;
        }
        else if(*end=='<')
        {
            _status=INPUT_REDIR;
            *end='\0';
            end++;
            break;
        }
        else{
            end--;
        }
    }
    if(end>=str)
    {
        return end;
    }
    else
        return NULL;
}
int main()
{
    extern char** environ;
    //0.shell不退出，需要用子进程执行命令
    while(1)
    {
        //1.打印提示符
        printf("[zhangsan@20220922 myshell]# ");
        fflush(stdout);
        memset(cmd_arg,'\0',sizeof cmd_arg);
        //2.接受命令行字符串
        if(fgets(cmd_arg,sizeof cmd_arg,stdin)==NULL)
            continue;
            //去除输入的回车/n
        cmd_arg[strlen(cmd_arg)-1]='\0';
        char* sep=check_redir(cmd_arg);
        //3.解析字符串
        g_val[0]=strtok(cmd_arg,SEP);//第一次调用传入解析字符串;
        int i=1;
        if(strcmp(g_val[0],"ls")==0)
        {
            g_val[i++]="--color=auto";
        }
        if(strcmp(g_val[0],"ll")==0)
        {
            g_val[0]="ls";
            g_val[i++]="-l";
            g_val[i++]="--color=auto";
        }
        while(g_val[i++]=strtok(NULL,SEP));//第二次还想解析原字符串，需要传入NULL
        if(strcmp(g_val[0],"export")==0&&g_val[1]!=NULL)
        {
            strcpy(my_val,g_val[1]);
            int ret=putenv(my_val);
            if(ret==0) printf("success: MYVAL=%s\n",getenv("MYVAL"));
            continue;

        }
        //4.执行内置命令---父进程执行
        if(strcmp(g_val[0],"cd")==0)
        {
           if(g_val[1]!=NULL) 
               chdir(g_val[1]);
        }
        //5.创建子进程执行其他进程命令
        pid_t id =fork();
        if(id==0)
        {
            //子进程
            printf("下面命令为子进程执行\n");
            if(sep!=NULL)
            {
                int fd=-1;
                switch(_status)
                {
                    case INPUT_REDIR:
                        {
                            fd=open(sep,O_RDONLY);
                            dup2(fd,0);
                            break;
                        }
                    case OUTPUT_REDIR:
                        {
                            fd=open(sep,O_WRONLY|O_TRUNC|O_CREAT,0666);
                            dup2(fd,1);
                            break;
                        }
                    case APPEND_REDIR:
                        {
                            fd=open(sep,O_WRONLY|O_CREAT|O_APPEND,0666);
                            dup2(fd,1);
                            break;
                        }
                    default:
                        printf("bug\n");
                        break;
                }
            }
            execvp(g_val[0],g_val);
            exit(1);
        }
        int status=0;
        pid_t res=waitpid(-1,&status,0);
        if(res>0)
            printf("exit code:%d\n",WEXITSTATUS(status));
    }
    return 0;
}
